package cc.mango.android.chart;

import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.achartengine.GraphicalView;
import org.achartengine.chart.AbstractChart;
import org.achartengine.chart.PointStyle;
import org.achartengine.chart.TimeChart;
import org.achartengine.model.TimeSeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import cc.mango.android.dto.StkIntraday;
import cc.mango.common.FinalKey;
import cc.mango.data.DataHelper;
import cc.telecomdigital.tdstock.CommonDefn;
import cc.telecomdigital.tdstock.ExceptionHandler;
import cc.telecomdigital.tdstock.ITDLApplication;
import cc.telecomdigital.tdstock.Framework.UniqueItem.TDStockLog;
import cc.telecomdigital.tdstock.view.SunFlowerView;

public final   class StkTimeView extends GraphicalView
{

	private final static String	TAG					= StkTimeView.class
														.getSimpleName();
	/** The chart to be drawn. */
	private TimeChart			nChart;

	//private  String stockCode;
	/** The user interface thread handler. */
	private Handler			mHandler;
	private String				_stockCode			= "";
	private Context			_context;
	private SharedPreferences	_prefsActivationCode;
	private static int			BACKGROUND_COLOR		= 0xff273866;
	private static int			FILL_BELOW_COLOR		= 0xff2a479a;
	private FetchAndDrawTask		_task;
	/*public  ItemCodeChangeListenerReceiver _itemCodeChangeListenerReceiver;*/
	private boolean			_isReadyForHandleMsg	= false;
	private boolean              _isReadyForUpdateImmediately = false;
	private View				selfView;
	private static long			_lastRuntime			= 0l;

	class RefreshHandler extends Handler
	{
		private static final long	DELAY_MILLIS		= 1000 * 60 * 60 *  60 * 24;   //don't update the chart by minutes
		//private static final long FROM_PAUSE_TO_RESUME_MILLIS = 1000 * 5;
		private static final long	DELAY_SHORT_TIME	= 300l;

		@Override
		public void handleMessage(Message msg)
		{

			/*	if (((ITDLApplication)_context.getApplicationContext()).isTimeChartInBackground()) {
					 super.handleMessage(msg);
					 _delayCounter = DELAY_MILLIS;  
					 sleep(FROM_PAUSE_TO_RESUME_MILLIS);
					 //sleep(DELAY_SHORT_TIME);
					 return;
				}*/

			//StkTimeView.this.invalidate();
			String tmpCode = ((ITDLApplication) _context
					.getApplicationContext()).getCurrentStockCode();
			//			 String userName =  ((ITDLApplication) _context.getApplicationContext()).getUserName(CommonDefn.SYSTEM_TRIAL_ACCOUNT_USER);
			//			 String userPwd =  ((ITDLApplication) _context.getApplicationContext()).getPwd(CommonDefn.SYSTEM_TRIAL_ACCOUNT_PWD);
			//			 String deviceId =  ((ITDLApplication) _context.getApplicationContext()).getDeviceId();  //commit by haibo, 2011-04-29
			if (tmpCode.equals(_stockCode))
			{
				/* _delayCounter += DELAY_SHORT_TIME;
				 if(_delayCounter >= DELAY_MILLIS) {
					 _delayCounter = 0;*/
				// TDStockLog.d(TAG, " update stock code:" + _stockCode   + "  by  one minute.");
				//						_stkList = DataHelper.getStkIntraListByCode(_stockCode, FinalKey.INTRADAY_DATETYPE_TODAY,userName,  userPwd);
				//						StkTimeView.this.repaint();

				if ( (System.currentTimeMillis() - _lastRuntime >= DELAY_MILLIS
						&& (_task == null || _task.getStatus() != AsyncTask.Status.RUNNING) ) || (_isReadyForUpdateImmediately))
				{
					if (!((ITDLApplication) _context
							.getApplicationContext())
							.isTimeChartInBackground())
					{
						if (_task != null)
						{
							_task.cancel(true);
							_task = null;
						}
						TDStockLog.d(TAG, "ready to update  stock code:"
								+ _stockCode + "  immediately！");
						_task = new FetchAndDrawTask();
						_task.execute(/*userName, userPwd,deviceId*/); //commit by haibo, 2011-04-29
						_isReadyForUpdateImmediately = false;
					}

				}

				/* } ;*/
				sleep(DELAY_SHORT_TIME);
			}
			else
			{
				_stockCode = tmpCode;
				//				   _delayCounter = 0;
				TDStockLog.d(TAG, "update stock code:" + _stockCode
						+ " immediately！");
				//					_stkList = DataHelper.getStkIntraListByCode(_stockCode, FinalKey.INTRADAY_DATETYPE_TODAY,userName,  userPwd);
				//					StkTimeView.this.repaint();
				
				//--------------reset the chart to empty after changing the code--------------
				if(_stkList != null)
					_stkList.clear();
				clearChartIfNeed();
				TDStockLog.d(TAG, "clear the chart first after changing the code!");
				//--------------reset the chart to empty after changing the code--------------

				if (!((ITDLApplication) _context.getApplicationContext())
						.isTimeChartInBackground())
				{
					if (_task != null)
					{
						_task.cancel(true);
						_task = null;
					}

					_task = new FetchAndDrawTask();
					_task.execute(); //commit by haibo, 2011-04-29
					_isReadyForUpdateImmediately = false;
					//  new FetchAndDrawTask().execute(userName, userPwd);
				}
			
			}

		}

		public void sleep(long delayMillis)
		{
			//sendEmptyMessageDelayed(0,delayMillis);  //to enter message handler looper after delayMillis
			while (!sendEmptyMessageDelayed(0, delayMillis))
			{ //force to wait delayMillis
				Thread.yield();
				//break; 
			}
			/*	long lastRuntime = System.currentTimeMillis();
				while(System.currentTimeMillis()-lastRuntime <= delayMillis) {
					Thread.yield();
				}
				this.sendEmptyMessage(0);*/
		}
	}

	private XYMultipleSeriesRenderer	_seriesRenderer;
	private List<StkIntraday>		_stkList;
	private String					_actCode;


	public StkTimeView(Context context, AbstractChart chart)
	{
		super(context, chart);
		TDStockLog.d(TAG, "one");
		init(context);
	}
    
	//fix bug on   java.lang.reflect.InvocationTargetException
	public StkTimeView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		TDStockLog.d(TAG, "two");
		init(context);
	}
	
	//fix bug on   java.lang.reflect.InvocationTargetException
	public StkTimeView(Context context, AttributeSet attrs, int defStyle) 
	{
		super(context, attrs, defStyle);
		TDStockLog.d(TAG, "three");
		init(context);		
	}
	
	
	
	

	//	private void registerReceiver(Context context) {
	/*if(_itemCodeChangeListenerReceiver == null)
	_itemCodeChangeListenerReceiver = new BroadcastReceiver() {
		
		@Override
		public void onReceive(Context context, Intent intent) {
			TDStockLog.d(TAG, " received intent item code changed,  starting to handle it");
			
			 new Thread() {

		            @Override
		            public void run() {
		            	if(mHandler!= null) {
		            		mHandler.sendEmptyMessage(0);  //forward to the message handler looper
		            	}
		                
		            }
		        }.start();
		}

	};*/

	/*	_itemCodeChangeListenerReceiver =  new ItemCodeChangeListenerReceiver(mHandler);
		
		try {
			IntentFilter filter =  new IntentFilter(CommonDefn.RECEIVER_ITEM_CODE_CHANGE);
			context.registerReceiver(_itemCodeChangeListenerReceiver, filter);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
	//	}

	private void init(Context context)
	{
		selfView = (View) this;
		mHandler = new RefreshHandler();
		ExceptionHandler.register(context);
		//		 registerReceiver(context);
		this.setDrawingCacheBackgroundColor(FILL_BELOW_COLOR);
		this.setDrawingCacheEnabled(true);
		this.setClickable(true);
		
		_seriesRenderer = getNominalRenderer();

		//this.stockCode = stockCode;
		try
		{
			
			_prefsActivationCode = context.getSharedPreferences(
					CommonDefn.SYSTEM_CURRENT_SETTING,
					Context.MODE_PRIVATE);
			_stockCode = ((ITDLApplication) context.getApplicationContext())
					.getCurrentStockCode();
			_context = context;

			_lastRuntime = System.currentTimeMillis();
			_actCode = _prefsActivationCode.getString(
					CommonDefn.PREFERENCE_TRIAL_ACTIVE_CODE, "");
		/*  mHandler.post(new Runnable() {
		      public void run() {
		    	    _stockCode = ((ITDLApplication) _context.getApplicationContext()).getCurrentStockCode();
		    	     TDStockLog.d("StkTimeView", "stock code=" + _stockCode );
					_stkList = DataHelper.getStkIntraListByCode(_stockCode);
					StkTimeView.this.repaint();
		    	  mHandler.postDelayed(this, 1000 * 60);
		      }
		  });*/

		

		//		 _oneFetchTask =  new FetchAndDrawTask();
		//		 _oneFetchTask.execute(userName, userPwd);
		//((RefreshHandler)mHandler).sleep(200);  //construct a message loop to update the chart;
		nChart = new TimeChart(new XYMultipleSeriesDataset(), _seriesRenderer);
		nChart.setDateFormat(FinalKey.HH_MM_FORMAT);
		super.setChart(nChart);
		new FetchAndDrawTask().execute();
		//mHandler.sendEmptyMessageDelayed(0, 500);
		// ((RefreshHandler)mHandler).sleep(300);  //construct a message loop to update the chart;

		////	    genNominalChart(DataHelper.getStkIntraListByCode(stockCode));
		//		super.setChart(nChart);
		//repaint();
		}
		catch (Exception e)
		{

		}
	}

	public StkTimeView(Context context/*, String stockCode*/)
	{
		super(context);
		init(context);
	}

	public void genNominalChart(List<StkIntraday> intraList)
	{

		_lastRuntime = System.currentTimeMillis();
		//--------haibo, 2011-07-26, if the list size < 1,  clear the chart;-----------
		
	/*	if (_stkList == null || _stkList.isEmpty())
		{
			TDStockLog.e(TAG, "the data is empty when ready for update!");
			//no reed to update the chart to empty. 
			return;
		}*/
		
		//--------haibo, 2011-07-26, if the list size < 1,  clear the chart;-----------
		
		this.setEnabled(false);
		XYMultipleSeriesDataset seriesDataset = getDatasetByStockCode(intraList);
		String dateFormat = FinalKey.HH_MM_FORMAT;
		if (nChart != null)
		{
			nChart = null;
		}
		nChart = new TimeChart(seriesDataset, _seriesRenderer);
		nChart.setDateFormat(dateFormat);
		super.setChart(nChart);
		this.setEnabled(true);
		//TDStockLog.e("gen chart again", "once again!" );
	}
	
	
	public void clearChartIfNeed()
	{
		this.setEnabled(false);
		XYMultipleSeriesDataset seriesDataset = getDatasetByStockCode( new ArrayList<StkIntraday>());
		String dateFormat = FinalKey.HH_MM_FORMAT;
		if (nChart != null)
		{
			nChart = null;
		}
		nChart = new TimeChart(seriesDataset, _seriesRenderer);
		nChart.setDateFormat(dateFormat);
		super.setChart(nChart);
		this.setEnabled(true);
		this.invalidate();
		//TDStockLog.e("gen chart again", "once again!" );
	}

	private XYMultipleSeriesRenderer getNominalRenderer()
	{
		XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();

		XYSeriesRenderer b = new XYSeriesRenderer();
		b.setPointStyle(PointStyle.POINT);
		b.setColor(Color.WHITE);
		b.setFillPoints(true);
		b.setFillBelowLineColor(FILL_BELOW_COLOR); //blue sky
		b.setFillBelowLine(true);
		renderer.addSeriesRenderer(b);
		renderer.setShowLegend(false);
		renderer.setShowLabels(false);
		renderer.setShowAxes(false);
		renderer.setShowGrid(false);
		/* renderer.setAxesColor(Color.DKGRAY);
		 renderer.setLabelsColor(Color.LTGRAY);*/
		renderer.setBackgroundColor(BACKGROUND_COLOR);
		renderer.setApplyBackgroundColor(true);
		renderer.setLegendSize(0);
		//renderer.setShowGrid(true);
		renderer.setLeftWidth(0);
		renderer.setRightWidth(0);
		renderer.setTopHeight(0);
		return renderer;
	}

	private XYMultipleSeriesDataset getDatasetByStockCode(
			List<StkIntraday> intraList)
	{
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();

		String seriesTitle = "";
		TimeSeries series = new TimeSeries(seriesTitle);
		//List<StkIntraday> stkList = DataHelper.getStkIntraListByCode(stockCode);
		String format = FinalKey.YEAR_MONTH_DAT_TIME_FORMAT;
		SimpleDateFormat formatter = new SimpleDateFormat(format);
		for (int i = 0; i < (intraList == null ? 0 : intraList.size()); i++)
		{
			StkIntraday dto = intraList.get(i);
			Date xDate = null;
			String xValue = dto.getDtyyyymmdd() + dto.getTime();
			//TDStockLog.e(TAG,String.format("xLabel : %s", xValue));
			try
			{
				//				xDate = StringUtils.string2Date(xValue,FinalKey.YEAR_MONTH_DAT_TIME_FORMAT);
				xDate = formatter.parse(xValue);
			}
			catch (Exception e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			series.add(xDate, dto.getClose());
		}

		dataset.addSeries(series);

		return dataset;
	}

	@Override
	protected void onDraw(Canvas canvas)
	{
		try{
		super.onDraw(canvas);
		}catch(Exception e){
			
		}
		//repaint();
	}

	/*public void reDrawtImmediately(){
		_stockCode =  ((ITDLApplication) _context.getApplicationContext()).getCurrentStockCode();
		_stkList = DataHelper.getStkIntraListByCode(_stockCode);
		repaint();
	}*/

	public void repaint()
	{

		//		if (((ITDLApplication)_context.getApplicationContext()).isTimeChartInBackground()) {
		//			return;
		//		}

		final Runnable job = new Runnable()
		{
			public void run()
			{
				genNominalChart(_stkList);
			}
		};

		/*   new Thread(){
		 	  public void run(){
		 		  boolean updated = false;
		 		  while(!updated) {
		 			  updated =  mHandler.post(job);
		 		  }
		 	  }
		   }.start();*/
		
		//---------------to avoid NullPointerException---------------	
		
		if(mHandler == null) {
			mHandler = new Handler();
		}

		boolean result = mHandler.post(job);
		   if(result &&  (_stkList != null) && _stkList.size() > 0) {
			 TDStockLog.d(TAG, "update successfully!");
		 }
		 else {
			 TDStockLog.e(TAG, "failed to update in repaint !");
		 }
		   
		   //---------------to avoid NullPointerException---------------
		super.repaint();
	}

	public void drawImmediately()
	{
		if (mHandler != null)
		{
			_isReadyForUpdateImmediately = true;
			mHandler.sendEmptyMessage(0); //forward to the message handler looper
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		return true;
	}

	private class FetchAndDrawTask extends AsyncTask<String, Void, Void>
	{
		private LinearLayout	_chart_waiting;
		private SunFlowerView	sunFlowerView2;
		private static final int RETRY_TIMES_TOTAL = 1;
		private int _retry_times = 0;
		
		public FetchAndDrawTask(){
			super();
		}
		
		
		
		@Override
		protected Void doInBackground(String... params)
		{
			//			if(_chart_waiting==null) startSunFlower();  //commit it by haibo, 2011-04-29
			boolean isExceptionAppear = false;
			try
			{
				_stkList = DataHelper.getStkIntraListByCode(_stockCode,
						FinalKey.INTRADAY_DATETYPE_TODAY, /*userName, userPwd,deviceId,*/
						_context.getApplicationContext(), _actCode);   //if there's a exception, the list was not modified!
				
				if(_stkList != null) {
					TDStockLog.d(TAG, "got the data and its size:" + _stkList.size() );
				}

			}
			catch (SocketTimeoutException e)
			{
				TDStockLog.e(TAG, e.getMessage()== null ? "SocketTimeoutException  in fetch data!" : e.getMessage());
				isExceptionAppear = true;
				e.printStackTrace();
				
			}
			catch (Exception e)
			{
				isExceptionAppear = true;
				TDStockLog.e(TAG, e.getMessage()== null ? "unkonwn exception in fetch data!" : e.getMessage());
			}
			
			if(isExceptionAppear && _retry_times  <  RETRY_TIMES_TOTAL) {
				_retry_times ++;
				doInBackground(params);  //retry it once again when there's a exception
			}
			return null;
		}

		private void startSunFlower()
		{
			try
			{
				//TDStockLog.d(TAG, "selfView="+selfView);
				if (_context != null && selfView != null)
				{
					if (_chart_waiting == null)
					{
						ViewGroup pt = (ViewGroup) selfView.getParent();
						if (pt != null)
						{
							_chart_waiting = (LinearLayout) (pt)
									.getChildAt(2);
						}
					}
					//TDStockLog.d(TAG, "onPreExecute()-> "+_chart_waiting);
					// add SunFlower Animation.
					if (_chart_waiting != null)
					{
						sunFlowerView2 = new SunFlowerView(_context);
						_chart_waiting.removeAllViews();
						_chart_waiting.addView(sunFlowerView2);
						sunFlowerView2.startAnimation();
						TDStockLog.d(TAG, "onPreExecute() -> startAnimation.");
					}
				}
			}
			catch (Exception e)
			{
				e.printStackTrace();
				TDStockLog.e(
								TAG,
								e.getMessage() == null ? "unkonwn exception instartSunFlower "
										: e.getMessage());
			}
		}

		@Override
		protected void onPreExecute()
		{
			super.onPreExecute();
			_retry_times = 0;
			startSunFlower();
		}

		@Override
		protected void onPostExecute(Void result)
		{
			super.onPostExecute(result);
			try
			{
				// clear SunFlower Animation.
				if (_chart_waiting != null && sunFlowerView2 != null)
				{
					sunFlowerView2.stopAnimation();
					_chart_waiting.removeAllViews();
					TDStockLog.d(TAG, "onPostExecute(result) -> stopAnimation.");
				}
			}
			catch (Exception e)
			{
				TDStockLog.e(
						TAG,
						e.getMessage() == null ? "unkonwn exception in onPostExecute! "
								: e.getMessage());
				e.printStackTrace();
			}
			/*if (_stkList == null)
			{
				TDStockLog.e(TAG, "the data is empty  after download!");
				return;
			}
			else
			{
				TDStockLog.e(TAG, "the data is not empty after download!");
			}*/
			
			//haibo, 2011-07-26, if the list size < 1,  clear the chart;
			final Runnable drawChart = new Runnable()
			{

				@Override
				public void run()
				{

					StkTimeView.this.repaint();
					if (!_isReadyForHandleMsg)
					{
						_isReadyForHandleMsg = true;

						if (mHandler != null && !Thread.interrupted())
						{
							mHandler.sendEmptyMessageDelayed(0, 500);
						}

						TDStockLog.d( TAG,
									"it is the first time to draw  chart, and it is in the constructor of Stock UI.");

					}

				}

			};

			new Thread()
			{

				@Override
				public void run()
				{
					if (mHandler != null && !Thread.interrupted())
					{
						boolean result = mHandler.post(drawChart);
						/* if(result) {
							 TDStockLog.d(TAG, "update successfully!");
						 }
						 else {
							 TDStockLog.e(TAG, "failed to update in onPostExecute !");
						 }*/
					}
				}

			}.start();

		}

	}

}
